
import java.io.*;
import java.util.*;
import java.util.concurrent.*;

class sortBySimilarity implements Comparator<User>{
    @Override
    public int compare(User o1, User o2) {
        if (o1.getJaccard() == o2.getJaccard()){//如果相似度相等
            return o1.getUserid().compareTo(o2.getUserid());//按照userId排序
        }
        //按照相似度从大到小排序
        if (o1.getJaccard() < o2.getJaccard()){
            return 1;
        }else {
            return -1;
        }
    }
}

public class testDemo {

    public static void main(String[] args) {
        testDemo t = new testDemo();
        t.readFile("review.txt");//读取文件
        Iterator<String> iterator = hashMap.keySet().iterator();//创建一个迭代器，用于取出每一个用户的userId
        myTask task = new myTask();//创建任务对象
        for (int i = 1; i <= hashMap.size(); i++) {//为每个用户ID创建一个线程
            Thread thread = new Thread(task);
            thread.setName(iterator.next());//设置线程的名字为当前用户的ID
            System.out.println("创建"+i);
            thread.start();//启动线程
            while (thread.isAlive()){}
            if (i%50==0){//每创建了50个线程，就让程序等一下，等到当前创建的第i个线程完成再继续
                while(thread.isAlive()){

                }
            }
        }
        try {
            countDownLatch.await();//等待子线程完成任务，主线程再执行任务
            t.writeFile("userNeighborhood.txt");//将数据写入文件中
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public static HashMap<String,HashSet<String>> hashMap = new HashMap<>();//用于存放读取的数据：userId、productId
    public static HashMap<String,ArrayList<String>> neighbor = new HashMap<>();//用于存放待写入的数据：userId、neighborId
    public static CountDownLatch countDownLatch;

    public static int no = 0;//用于计数已经完成的线程
    static class myTask implements Runnable {
        @Override
        public void run() {
            String userId = Thread.currentThread().getName();//获取当前线程负责计算的userId
            HashSet<String> pro = hashMap.get(userId);//获得userId购买的产品清单
            ArrayList<User> neighborhood = new ArrayList<>();//用于存放与其他用户计算得到的相似度
            for (String s:hashMap.keySet()) {//遍历其他用户
                if (s==userId){
                    continue;
                }
                HashSet<String> p = hashMap.get(s);//获得其他用户购买的产品清单
                //求相似度
                HashSet<String> a = (HashSet<String>) p.clone();
                a.addAll(pro);//求∪
                HashSet<String> b = (HashSet<String>) p.clone();
                b.retainAll(pro);//求∩
                double Jaccard = b.size()*(1.0)/a.size();//计算相似度
                User user = new User(s,Jaccard);//将userId和相似度放到一个User对象中
                neighborhood.add(user);//将user添加到neighborhood中
            }
            neighborhood.sort(new sortBySimilarity());//按相似度大小进行排序
            ArrayList<String> n = new ArrayList<>();//创建一个ArrayList类 - 用于存放相似度最高的前十名userId
            for (int i = 0; i < 10; i++) {
                n.add(neighborhood.get(i).getUserid());//取出相似度前十名
            }
            neighbor.put(userId,n);//将相似度最高的前十名用户列表和当前用户一起放到待写入的hashmap中
            countDownLatch.countDown();
            no++;
            System.out.println(no+"完成！");
        }
    }

    public void readFile(String fileName) {
        try {//读文件
            FileReader fr = new FileReader(fileName);
            BufferedReader input = new BufferedReader(fr);
            int i = 0;//用于记录读取的userId数量
            String s = null;//用于存放每次读取的内容
            String pro = null;//用于存放读到的productId
            String usr = null;//用于存放读到的userId
            while ((s = input.readLine()) != null) {//循环直到读取结束
                    StringTokenizer s1 = new StringTokenizer(s, ";");//用StringTokenizer对象进行分割
                    usr = s1.nextToken();//将userId的内容放到usr中
                    pro = s1.nextToken();//将productId的内容放到pro中
                    s1.nextToken();//将前面不需要的内容读走
                    //将数据存放到hashMap中
                    if (hashMap.containsKey(usr)) {//如果hashMap中已经包含该userId
                        HashSet<String> product = hashMap.get(usr);//则取出该userId对应的product列表
                        product.add(pro);//将productId放入
                        hashMap.put(usr, product);//将键值对放入hashMap中
                    } else {//如果hashMap中不包含该userId
                        HashSet<String> product = new HashSet<>();//则创建一个product列表
                        product.add(pro);//将productId放入
                        hashMap.put(usr, product);//将新的键值对放入hashMap中
                        i++;//userId数量+1
                    }
                }
            System.out.println(i);//输出userId数量
            fr.close();
            input.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        countDownLatch = new CountDownLatch(hashMap.size());
    }

    public void writeFile(String fileName){
        try {
            FileWriter fw = new FileWriter(fileName);
            BufferedWriter output = new BufferedWriter(fw);
            ArrayList<String> strings = new ArrayList<>(hashMap.keySet());
            strings.sort(Comparator.naturalOrder());//对userId进行排序
            for (String s:strings) {//按顺序取出每个userId
                //将该userId和与其相似度最大的10个用户写入，用";"隔开
                output.write(s+";");
                for (String str:neighbor.get(s)) {
                    output.write(str+";");
                }
                output.newLine();//换行
            }
            output.flush();//刷新
            output.close();
            fw.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

